home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-03-29 | 11.0 KB | 352 lines | [TEXT/PJMM] |
- {SATGridToolbox}
- {}
- {Routines for SAT-based games with a game world defined by a grid.}
- {Note that this is the "Oxyd"-style world, where movement isn't contrained to the grid,}
- {but obstacles etc are defined by it. It is NOT ment for strict grid movement, as in PacMan!}
- {}
- {Limitations and assumptions:}
- {• Your grid is defined in the unit SATGridStubs.}
- {• All free space grid values are smaller than the blocked ones. (Specified by kFreeSpace.) }
- {• Sprites should not be bigger (wider/higher) than the grid spaces. (Sprites only check with the}
- {corners of the hotRects, which mens that a small grid obstacle could pass right through it!)}
- {}
- {Idéer:}
- {• Lägg till rutiner för förflyttning och kollisionshantering i strikt grid. Eller skall det vara en}
- {egen modul?}
- {• Duger LoadGrid?}
- {• Prefix på namnen?}
-
- unit SATGridToolbox;
-
- interface
-
- uses
- {$IFC UNDEFINED THINK_PASCAL}
- Types, QuickDraw, Fonts, Events, Packages, Menus, Dialogs, Windows,{}
- OSUtils, ToolUtils, {OSEvents,}
- Resources,
- {$ENDC}
- SAT, SATToolbox, SATGridStubs;
-
- procedure MoveSpriteInGrid (theSprite: FixSpritePtr);
- {procedure HitSprite (theSprite: FixSpritePtr; anotherSprite: FixSpritePtr); SKIT?}
- function Pt2GridValue (p: Point): GridSpaceType;
- procedure LoadGrid (resNum: Integer);
- procedure DrawAllTiles;
- function PtInGrid (p: Point): Boolean;
- procedure GridTest (theSprite: FixSpritePtr);
-
- implementation
-
- {Load the grid from a TEXT resource.}
- procedure LoadGrid (resNum: Integer);
- type
- CharArr = packed array[0..99999] of Char;
- CharArrPtr = ^CharArr;
- CharArrHnd = ^CharArrPtr;
- var
- hnd: CharArrHnd;
- howMuch: Longint;
- h, v: Integer;
- begin
- hnd := CharArrHnd(GetResource('TEXT', resNum));
- if hnd = nil then
- exit(LoadGrid);
- if GetHandleSize(Handle(hnd)) > SizeOf(tileArray) then
- howMuch := SizeOf(tileArray)
- else
- howMuch := GetHandleSize(Handle(hnd));
-
- HLock(Handle(hnd));
-
- h := 0;
- v := 0;
- howMuch := 0;
-
- while howMuch < GetHandleSize(Handle(hnd)) do
- begin
- if hnd^^[howMuch] = Char(13) then
- begin
- h := 0;
- v := v + 1;
- end
- else
- begin
- if h < kArraySizeH then
- if v < kArraySizeV then
- tileArray[h, v] := hnd^^[howMuch];
- h := h + 1;
- end;
-
- howMuch := howMuch + 1;
- end;
-
- HUnLock(Handle(hnd));
-
- {BlockMove(Ptr(hnd^), @tileArray[0, 0], howMuch);}
- ReleaseResource(Handle(hnd));
- end; {LoadGrid}
-
- {PtInGrid: is the point blocked or free?}
- {Needs improving: several different grid values should be free!}
-
- function PtInGrid (p: Point): Boolean;
- begin
- PtInGrid := tileArray[p.h div kTileSizeH][p.v div kTileSizeV] > kFreeSpace;
- end; (*PtInGrid*)
-
-
- {Get the grid value in a point. A sprite can, for example, test with its center!}
-
- function Pt2GridValue (p: Point): GridSpaceType;
- begin
- Pt2GridValue := tileArray[p.h div kTileSizeH][p.v div kTileSizeV];
- end; (*Pt2GridValue*)
-
- procedure GetGridRect (p: Point; var r: Rect);
- begin
- SetRect(r, p.h div kTileSizeH * kTileSizeH, p.v div kTileSizeV * kTileSizeV, (p.h div kTileSizeH + 1) * kTileSizeH, (p.v div kTileSizeV + 1) * kTileSizeV);
- end; (*GetGridRect*)
-
- function RectSeparateRect (theSprite: SpritePtr; var anotherRect: Rect): Integer;
- var
- distance: array[0..3] of Integer;
- shortest, shortestDistance, i: Integer;
- bounds1, bounds2: Rect;
- begin
- bounds1 := theSprite^.hotRect;
- OffsetRect(bounds1, theSprite^.position.h, theSprite^.position.v);
-
- bounds2 := anotherRect;
-
- (*Calculate the distance to separate the sprites in every direction*)
- distance[0] := bounds2.top - bounds1.bottom; {up}
- distance[1] := bounds2.bottom - bounds1.top; {down}
- distance[2] := bounds2.right - bounds1.left; {right}
- distance[3] := bounds2.left - bounds1.right; {left}
-
- (*Find the shortest distance*)
- shortest := 0;
- shortestDistance := abs(distance[0]);
- for i := 1 to 3 do
- if abs(distance[i]) < shortestDistance then
- begin
- shortest := i;
- shortestDistance := abs(distance[i]);
- end;
-
- (*Move the sprite in the appropriate direction*)
- case shortest of
- 0, 1:
- theSprite^.position.v := theSprite^.position.v + distance[shortest];
- 2, 3:
- theSprite^.position.h := theSprite^.position.h + distance[shortest];
- end; {case}
- RectSeparateRect := shortest;
- end; (*RectSeparateRect*)
-
-
- {GridTest: A complex function that tests whether a sprite is in free space or not, and bounces}
- {off grid obstacles if not.}
-
- procedure GridTest (theSprite: FixSpritePtr);
- var
- p1, p2, p3, p4: Point;
- bounds, gridRect: Rect;
- sum: Integer;
- begin
- sum := 0;
- bounds := theSprite^.hotRect;
- OffsetRect(bounds, theSprite^.position.h, theSprite^.position.v);
- p1 := bounds.topLeft;
- p2.h := bounds.left;
- p2.v := bounds.bottom;
- p3.h := bounds.right;
- p3.v := bounds.top;
- p4 := bounds.botRight;
-
- if PtInGrid(p1) then
- sum := sum + 1;
- if PtInGrid(p2) then
- sum := sum + 2;
- if PtInGrid(p3) then
- sum := sum + 4;
- if PtInGrid(p4) then
- sum := sum + 8;
-
- case sum of
- 0, 15:
- Exit(GridTest);
- { Single corner}
- 1:
- begin
- GetGridRect(p1, gridRect);
- if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
- theSprite^.speed.h := abs(theSprite^.speed.h)
- else
- theSprite^.speed.v := abs(theSprite^.speed.v);
- end;
- 2:
- begin
- GetGridRect(p2, gridRect);
- if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
- theSprite^.speed.h := abs(theSprite^.speed.h)
- else
- theSprite^.speed.v := -abs(theSprite^.speed.v);
- end;
- 4:
- begin
- GetGridRect(p3, gridRect);
- if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
- theSprite^.speed.h := -abs(theSprite^.speed.h)
- else
- theSprite^.speed.v := abs(theSprite^.speed.v);
- end;
- 8:
- begin
- GetGridRect(p4, gridRect);
- if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
- theSprite^.speed.h := -abs(theSprite^.speed.h)
- else
- theSprite^.speed.v := -abs(theSprite^.speed.v);
- end;
- { Sides}
- 3: {left}
- begin
- theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
- theSprite^.speed.h := abs(theSprite^.speed.h);
- end;
- 5: { top}
- begin
- theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
- theSprite^.speed.v := abs(theSprite^.speed.v);
- end;
- 10: { bottom}
- begin
- theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
- theSprite^.speed.v := -abs(theSprite^.speed.v);
- end;
- 12: { right}
- begin
- theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
- theSprite^.speed.h := -abs(theSprite^.speed.h);
- end;
-
- { three corners}
- 7: {bottom right free}
- begin
- theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
- theSprite^.speed.h := abs(theSprite^.speed.h);
- theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
- theSprite^.speed.v := abs(theSprite^.speed.v);
- end;
- 11: { top right free}
- begin
- theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
- theSprite^.speed.h := abs(theSprite^.speed.h);
- theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
- theSprite^.speed.v := -abs(theSprite^.speed.v);
- end;
- 13: { bottom left free}
- begin
- theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
- theSprite^.speed.h := -abs(theSprite^.speed.h);
- theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
- theSprite^.speed.v := abs(theSprite^.speed.v);
- end;
- 14: { top left free}
- begin
- theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
- theSprite^.speed.h := -abs(theSprite^.speed.h);
- theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
- theSprite^.speed.v := -abs(theSprite^.speed.v);
- end;
- 6: { diagonal}
- begin
- if theSprite^.speed.h + theSprite^.speed.v > 0 then { if down-right speed}
- begin
- theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
- theSprite^.speed.h := -abs(theSprite^.speed.h);
- theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
- theSprite^.speed.v := -abs(theSprite^.speed.v);
- end
- else { else up-left speed}
- begin
- theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
- theSprite^.speed.h := abs(theSprite^.speed.h);
- theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
- theSprite^.speed.v := abs(theSprite^.speed.v);
- end;
- end;
- 9: { diagonal}
- begin
- if theSprite^.speed.h - theSprite^.speed.v > 0 then { if up-right speed}
- begin
- theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
- theSprite^.speed.h := -abs(theSprite^.speed.h);
- theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
- theSprite^.speed.v := abs(theSprite^.speed.v);
- end
- else { else down-left speed}
- begin
- theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
- theSprite^.speed.h := -abs(theSprite^.speed.h);
- theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
- theSprite^.speed.v := abs(theSprite^.speed.v);
- end;
- end;
- end; {case}
- theSprite^.fixedPointPosition.h := BSL(theSprite^.position.h, 4);
- theSprite^.fixedPointPosition.v := BSL(theSprite^.position.v, 4);
- end; (*GridTest*)
-
- var
- firstFace, secondFace, thirdFace: GrafPtr;
-
- procedure MoveSpriteInGrid (theSprite: FixSpritePtr);
- { theSprite->speed.v++; // Simple gravity}
- begin
- theSprite^.fixedPointPosition.h := theSprite^.fixedPointPosition.h + theSprite^.speed.h;
- theSprite^.fixedPointPosition.v := theSprite^.fixedPointPosition.v + theSprite^.speed.v;
- theSprite^.position.h := BSR(theSprite^.fixedPointPosition.h, 4);
- theSprite^.position.v := BSR(theSprite^.fixedPointPosition.v, 4);
- GridTest(theSprite);
- if KeepOnScreenFixed(theSprite) then
- ;
- end; (*MoveSpriteInGrid*)
-
-
- {Standard rect-based bounce-off collision handling.}
- {VAD ÄR DETTA FÖR SKIT???}
- {This routine seems to have been left here by mistake. I'll nuke it when I feel 100% sure.}
- procedure HitSprite (theSprite: FixSpritePtr; anotherSprite: FixSpritePtr);
- var
- tempSpeed: Integer;
- begin
- if RectSeparate(SpritePtr(theSprite), SpritePtr(anotherSprite), kPushBoth) >= 2 then { 2 or 3: horizontal, otherwise vertical}
- begin
- tempSpeed := theSprite^.speed.h;
- theSprite^.speed.h := anotherSprite^.speed.h;
- anotherSprite^.speed.h := tempSpeed;
- theSprite^.fixedPointPosition.h := BSL(theSprite^.position.h, 4);
- end
- else
- begin
- tempSpeed := theSprite^.speed.v;
- theSprite^.speed.v := anotherSprite^.speed.v;
- anotherSprite^.speed.v := tempSpeed;
- theSprite^.fixedPointPosition.v := BSL(theSprite^.position.v, 4);
- end;
- end; (*HitSprite*)
-
-
- procedure DrawAllTiles;
- var
- h, v: Integer;
- begin
- for h := 0 to kArraySizeH - 1 do
- for v := 0 to kArraySizeV - 1 do
- DrawTile(h, v);
- end; {DrawAllTiles}
-
- end.